{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b23ced4e-dc29-43be-9f94-0c36bb181b8a",
   "metadata": {},
   "source": [
    "# How to stream events from within a tool"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7044eeb8-4074-4f9c-8a62-962488744557",
   "metadata": {},
   "source": [
    "If your LangGraph graph needs to use tools that call LLMs (or any other LangChain `Runnable` objects -- other graphs, LCEL chains, retrievers, etc.), you might want to stream events from the underlying `Runnable`. This guide shows how you can do that."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a37f60af-43ea-4aa6-847a-df8cc47065f5",
   "metadata": {},
   "source": [
    "## Setup\n",
    "\n",
    "```bash\n",
    "npm install @langchain/langgraph @langchain/anthropic @langchain/core zod\n",
    "```\n",
    "\n",
    "```typescript\n",
    "process.env.ANTHROPIC_API_KEY = 'YOUR_API_KEY'\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3d02ebb-c2e1-4ef7-b187-810d55139317",
   "metadata": {},
   "source": [
    "## Define graph and tools"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d74a1760-a063-4d05-8c6f-9d16bc31fa82",
   "metadata": {},
   "source": [
    "We'll use a prebuilt ReAct agent for this guide"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "2cb38dd9-74d8-456d-9e39-4655f2bf3f37",
   "metadata": {},
   "outputs": [],
   "source": [
    "import { z } from \"zod\";\n",
    "import { tool } from \"@langchain/core/tools\";\n",
    "import { ChatPromptTemplate } from \"@langchain/core/prompts\";\n",
    "import { ChatAnthropic } from \"@langchain/anthropic\";\n",
    "\n",
    "const model = new ChatAnthropic({\n",
    "  model: \"claude-3-5-sonnet-20240620\",\n",
    "  temperature: 0,\n",
    "});\n",
    "\n",
    "const getItems = tool(\n",
    "  async (input, config) => {\n",
    "    const template = ChatPromptTemplate.fromMessages([\n",
    "      [\n",
    "        \"human\",\n",
    "        \"Can you tell me what kind of items i might find in the following place: '{place}'. \" +\n",
    "          \"List at least 3 such items separating them by a comma. And include a brief description of each item..\",\n",
    "      ],\n",
    "    ]);\n",
    "\n",
    "    const modelWithConfig = model.withConfig({\n",
    "      runName: \"Get Items LLM\",\n",
    "      tags: [\"tool_llm\"],\n",
    "    });\n",
    "\n",
    "    const chain = template.pipe(modelWithConfig);\n",
    "    const result = await chain.invoke(input, config);\n",
    "    return result.content;\n",
    "  },\n",
    "  {\n",
    "    name: \"get_items\",\n",
    "    description: \"Use this tool to look up which items are in the given place.\",\n",
    "    schema: z.object({\n",
    "      place: z.string().describe(\"The place to look up items for. E.g 'shelf'\"),\n",
    "    }),\n",
    "  }\n",
    ");"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "17279b8a-049d-483d-af63-8a875098e71f",
   "metadata": {},
   "source": [
    "We're adding a custom tag (`tool_llm`) to our LLM runnable within the tool. This will allow us to filter events that we'll stream from the compiled graph (`agent`) Runnable below"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "7254310e-7016-45f7-9795-6d52a1160086",
   "metadata": {},
   "outputs": [],
   "source": [
    "import { createReactAgent } from \"@langchain/langgraph/prebuilt\";\n",
    "\n",
    "const agent = createReactAgent({\n",
    "  llm: model,\n",
    "  tools: [getItems],\n",
    "});"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7d88960-a66b-4699-adee-c12d40b4318a",
   "metadata": {},
   "source": [
    "## Stream events from the graph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "4399d9e9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ type: 'ai', content: 'Here' }\n",
      "{ type: 'ai', content: ' are three items you might' }\n",
      "{ type: 'ai', content: ' find on a shelf,' }\n",
      "{ type: 'ai', content: ' along with brief' }\n",
      "{ type: 'ai', content: ' descriptions:\\n\\n1.' }\n",
      "{ type: 'ai', content: ' Books' }\n",
      "{ type: 'ai', content: ': Boun' }\n",
      "{ type: 'ai', content: 'd collections of printe' }\n",
      "{ type: 'ai', content: 'd pages' }\n",
      "{ type: 'ai', content: ' containing' }\n",
      "{ type: 'ai', content: ' various' }\n",
      "{ type: 'ai', content: ' forms' }\n",
      "{ type: 'ai', content: ' of literature, information' }\n",
      "{ type: 'ai', content: ', or reference' }\n",
      "{ type: 'ai', content: ' material.\\n\\n2.' }\n",
      "{ type: 'ai', content: ' Picture' }\n",
      "{ type: 'ai', content: ' frames: Decorative' }\n",
      "{ type: 'ai', content: ' borders' }\n",
      "{ type: 'ai', content: ' used to display an' }\n",
      "{ type: 'ai', content: 'd protect photographs, artwork' }\n",
      "{ type: 'ai', content: ', or other visual memor' }\n",
      "{ type: 'ai', content: 'abilia.\\n\\n3' }\n",
      "{ type: 'ai', content: '. Pot' }\n",
      "{ type: 'ai', content: 'ted plants: Small' }\n",
      "{ type: 'ai', content: ' indoor' }\n",
      "{ type: 'ai', content: ' plants in' }\n",
      "{ type: 'ai', content: ' containers, often used for' }\n",
      "{ type: 'ai', content: ' decoration or to add a' }\n",
      "{ type: 'ai', content: ' touch of nature to indoor' }\n",
      "{ type: 'ai', content: ' spaces.' }\n"
     ]
    }
   ],
   "source": [
    "let finalEvent;\n",
    "\n",
    "for await (const event of agent.streamEvents(\n",
    "  {\n",
    "    messages: [\n",
    "      [\n",
    "        \"human\",\n",
    "        \"what items are on the shelf? You should call the get_items tool.\",\n",
    "      ],\n",
    "    ],\n",
    "  },\n",
    "  {\n",
    "    version: \"v2\",\n",
    "  },\n",
    "  {\n",
    "    includeTags: [\"tool_llm\"],\n",
    "  }\n",
    ")) {\n",
    "  if (\"chunk\" in event.data) {\n",
    "    console.dir({\n",
    "      type: event.data.chunk._getType(),\n",
    "      content: event.data.chunk.content,\n",
    "    })\n",
    "  }\n",
    "  finalEvent = event;\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ebd8902e-935b-4724-8b5d-551b7674fd34",
   "metadata": {},
   "source": [
    "Let's inspect the last event to get the final list of messages from the agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "ca382c1f-b1c7-4c8a-bd9b-7a873b891b3e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  type: 'ai',\n",
      "  content: 'Here are three items you might find on a shelf, along with brief descriptions:\\n' +\n",
      "    '\\n' +\n",
      "    '1. Books: Bound collections of printed pages containing various forms of literature, information, or reference material.\\n' +\n",
      "    '\\n' +\n",
      "    '2. Picture frames: Decorative borders used to display and protect photographs, artwork, or other visual memorabilia.\\n' +\n",
      "    '\\n' +\n",
      "    '3. Potted plants: Small indoor plants in containers, often used for decoration or to add a touch of nature to indoor spaces.',\n",
      "  tool_calls: []\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "const finalMessage = finalEvent?.data.output;\n",
    "console.dir(\n",
    "  {\n",
    "    type: finalMessage._getType(),\n",
    "    content: finalMessage.content,\n",
    "    tool_calls: finalMessage.tool_calls,\n",
    "  },\n",
    "  { depth: null }\n",
    ");\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d7f9457c-5665-4cd5-9a99-d54c84270616",
   "metadata": {},
   "source": [
    "You can see that the content of the `ToolMessage` is the same as the output we streamed above"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "TypeScript",
   "language": "typescript",
   "name": "tslab"
  },
  "language_info": {
   "codemirror_mode": {
    "mode": "typescript",
    "name": "javascript",
    "typescript": true
   },
   "file_extension": ".ts",
   "mimetype": "text/typescript",
   "name": "typescript",
   "version": "3.7.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
